﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SemenQuest.SubWindows
{
    public partial class VerticalTextButton : Button
    {
        [Category("Appearance")]
        [DefaultValue(0)]
        [Description("Angle of the text")]
        public Int32 RotateAngle
        {
            get { return _RotateAngle; }
            set
            {
                Int32 normalAngle = ((value % 360) + 360) % 360;
                if (_RotateAngle != normalAngle)
                {
                    _RotateAngle = normalAngle;
                    Invalidate();
                }
            }
        }
        private Int32 _RotateAngle = 0;

        [Category("Appearance")]
        [Description("The textl associated with the control")]
        public String Label
        {
            get { return _Label; }
            set
            {
                _Label = value;
                Invalidate();
            }
        }
        private String _Label;

        [Category("Appearance")]
        [DefaultValue(typeof(ArrowDirections), "Right")]
        [Description("State of the directionarrows")]
        public ArrowDirections ArrowDirection
        {
            get { return _ArrowDirection; }
            set
            {
                _ArrowDirection = value;
                Invalidate();
            }
        }
        private ArrowDirections _ArrowDirection = ArrowDirections.Right;

        public enum ArrowDirections : int
        {
            Right = 0,
            Left = 1
        }

        [Category("Appearance")]
        [DefaultValue(true)]
        [Description("Show direction arrows")]
        public Boolean ArrowsShow
        {
            get { return _ArrowsShow; }
            set
            {
                _ArrowsShow = value;
                Invalidate();
            }
        }
        private Boolean _ArrowsShow = true;

        [Category("Appearance")]
        [DefaultValue(typeof(UInt32), "50")]
        [Description("Distance between direction arrows")]
        public UInt32 ArrowsDistance
        {
            get { return _ArrowsDistance; }
            set
            {
                if (value == 0)
                    value = 1;
                _ArrowsDistance = value;
                Invalidate();
            }
        }
        private UInt32 _ArrowsDistance = 50;

        [Category("Appearance")]
        [DefaultValue(typeof(Color), "Silver")]
        [Description("Color of the direction arrows")]
        public Color ArrowsColor
        {
            get { return _ArrowsColor; }
            set
            {
                _ArrowsColor = value;
                Invalidate();
            }
        }
        private Color _ArrowsColor = Color.Silver;

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            //1. get size of string and calculate shift of rotationpoint, so text won't 
            //   rotate outside the control area
            Func<Double, Double> DegToRad = (angle) => Math.PI * angle / 180.0;
            SizeF size = e.Graphics.MeasureString(_Label, this.Font);

            Double normaleRads = DegToRad(_RotateAngle);
            Int32 hSinTheta = (Int32)Math.Ceiling((size.Height * Math.Sin(normaleRads)));
            Int32 wCosTheta = (Int32)Math.Ceiling((size.Width * Math.Cos(normaleRads)));
            Int32 wSinTheta = (Int32)Math.Ceiling((size.Width * Math.Sin(normaleRads)));
            Int32 hCosTheta = (Int32)Math.Ceiling((size.Height * Math.Cos(normaleRads)));
            Int32 rotatedWidth = Math.Abs(hSinTheta) + Math.Abs(wCosTheta);
            Int32 rotatedHeight = Math.Abs(wSinTheta) + Math.Abs(hCosTheta);

            Int32 horizShift = 0;
            Int32 vertShift = 0;
            if (_RotateAngle >= 0 && _RotateAngle < 90)
            {
                horizShift = Math.Abs(hSinTheta);
            }
            else if (_RotateAngle >= 90 && _RotateAngle < 180)
            {
                horizShift = rotatedWidth;
                vertShift = Math.Abs(hCosTheta);
            }
            else if (_RotateAngle >= 180 && _RotateAngle < 270)
            {
                horizShift = Math.Abs(wCosTheta);
                vertShift = rotatedHeight;
            }
            else if (_RotateAngle >= 270 && _RotateAngle < 360)
            {
                vertShift = Math.Abs(wSinTheta);
            }

            //2. Take text alignment point into account
            float X = 0, Y = 0;
            String name = Enum.GetName(typeof(ContentAlignment), TextAlign);
            X = name.Contains("Center") ? (this.Width - rotatedWidth) / 2 :
                name.Contains("Right") ? this.Width - rotatedWidth :
                0;
            Y = name.Contains("Middle") ? (this.Height - rotatedHeight) / 2 :
                name.Contains("Bottom") ? this.Height - rotatedHeight :
                0;

            if (ArrowsShow)
            {
                //1. get number of possible arrows in each area
                Int32 nrArrows = (Int32)Math.Floor((Double)(this.Height - rotatedHeight) / 2 / _ArrowsDistance);
                nrArrows = nrArrows % 2 == 0 ? nrArrows - 1 : nrArrows;
                if (nrArrows > 0)
                {
                    List<Int32> yValues = new List<Int32>();
                    Size arrowSize = e.Graphics.MeasureString("<", this.Font).ToSize();

                    Int32 qHeight = (this.Height - rotatedHeight) / 4;
                    Int32 aHeight = arrowSize.Height / 2;
                    Int32 distance = qHeight * 2 / nrArrows;
                    yValues.Add(qHeight - aHeight);
                    yValues.Add(this.Height - qHeight - aHeight);
                    for (Int32 j = 1; j <= (nrArrows - 1) / 2; j++) //Top arrows
                    {
                        yValues.Add(qHeight + j * distance - aHeight);
                        yValues.Add(qHeight - j * distance - aHeight);
                    }
                    for (Int32 j = 1; j <= (nrArrows - 1) / 2; j++) //Bottom arrows
                    {
                        yValues.Add(this.Height - qHeight + j * distance - aHeight);
                        yValues.Add(this.Height - qHeight - j * distance - aHeight);
                    }
                    String arrow = ArrowDirection == ArrowDirections.Left ? "<" : ">";

                    Int32 xValue = (this.Width - arrowSize.Width) / 2;
                    using (Brush b = new SolidBrush(_ArrowsColor))
                    {
                        foreach (Int32 yValue in yValues)
                        {
                            e.Graphics.DrawString(arrow, this.Font, b, xValue, yValue);
                        }
                    }
                }
            }


            //3. Draw string 
            using (Brush b = new SolidBrush(this.ForeColor))
            {
                e.Graphics.TranslateTransform(horizShift + X, vertShift + Y);
                e.Graphics.RotateTransform(_RotateAngle);
                e.Graphics.DrawString(_Label, this.Font, b, 0, 0);
            }
        }
    }
}
